package com.minidota.db;

import com.minidota.settings.Settings;
import java.sql.*;
import java.util.Properties;
import javax.sql.*;
import javax.naming.*;
import oracle.ucp.jdbc.*;
//import com.mysql.jdbc.*;


public class Connector {

    private static DataSource ds = null;

    static {
        try {
            ds = getDataSource();
            ds.getConnection().close(); //staring pool
        } catch (SQLException e) {
            System.out.println(e);
        }
    }

    /**
     * Образует соединение с базой данных через JDBC драйвер менеджер
     * и возвращает java.sql.Connection в случае успеха.
     *
     *	@param driverName  JDBC драйвер, используемый для установки соединения
     *	@param databaseURL URL для соединения с базой данных
     *	@param userName    имя пользователя
     *	@param password    пароль
     * @return
     */
    public Connection getConnection(String driverName, String databaseURL, String userName, String password) {
        Connection dbConnection = null;
      
        try {
            // Загрузим JDBC драйвер
            Class.forName(driverName);
        } catch (Exception e) {
            System.out.println("Unable to load JDBC driver: " + driverName + ". Exception: " + e);
        }
        try {
           // Class.forName ("com.mysql.jdbc.Driver").newInstance ();
            // Установим соединение с базой данных
            dbConnection = DriverManager.getConnection(databaseURL, userName, password);
            //System.out.println("Open database connection.");
        } catch (Exception e) {
            System.out.println("Unable to estblish connection through JDBC driver. JDBC driver: Exception: " + e);
        }
        return dbConnection;
    }

    /**
     * Образует соединение с базой данных через defaultCoreDS источник данных
     * и возвращает java.sql.Connection в случае успеха.
     * @return
     */
    public static Connection getConnection() {
        //return getConnection(defaultDSName);
        //return getConnection(defaultDriverName, defaultURL, defaultUser, defaultPassword);
        return getConnectionODS();
    }

    private static synchronized DataSource getDataSource() throws SQLException {
        PoolDataSource pds = PoolDataSourceFactory.getPoolDataSource();
        pds.setConnectionFactoryClassName(Settings.getString("connection.DriverClassName"));
        pds.setUser(Settings.getString("connection.Username"));
        pds.setPassword(Settings.getString("connection.Password"));
        pds.setURL(Settings.getString("connection.Url"));

        Properties prop = new Properties();
        prop.put(oracle.net.ns.SQLnetDef.TCP_CONNTIMEOUT_STR, Integer.toString(5000));
        pds.setConnectionProperties(prop);
        pds.setLoginTimeout(10);

        pds.setMinPoolSize(Settings.getInt("connection.MinLimit"));
        pds.setMaxPoolSize(Settings.getInt("connection.MaxLimit"));
        pds.setInitialPoolSize(Settings.getInt("connection.InitialLimit"));
        pds.setInactiveConnectionTimeout(5 * 60);
        pds.setAbandonedConnectionTimeout(20 * 60);
        pds.setTimeoutCheckInterval(60);
		pds.setValidateConnectionOnBorrow(true);

        return pds;
    }

    /**
     * Образует соединение с базой данных через ODS драйвер менеджер
     * и возвращает java.sql.Connection в случае успеха.
     * @return
     */
    public static Connection getConnectionODS() {
        try {
            if (ds == null) {
                synchronized (Connector.class) {
                    if (ds == null) {
                        ds = getDataSource();
                    }
                }
            }
            return ds.getConnection();
        } catch (Exception e) {
            System.out.println("Exception, Unable to establish connection through ODS: " + e);
            for (int i = 0; i < 5; i++) {
                try {
                    return ds.getConnection();
                } catch (Exception ex) {
                    System.out.println(ex);
                    try {
                        Thread.sleep(60);
                    } catch (InterruptedException ie) {
                    }
                }
            }
            return null;
        }
    }

    /**
     * Образует соединение с базой данных через источник данных
     * и возвращает java.sql.Connection в случае успеха.
     *
     *	@param dsName  имя источника данных
     * @return
     */
    public Connection getConnection(String dsName) {
        Connection dbConnection = null;
        try {
            // Установим соединение с базой данных
            InitialContext initialContext = new InitialContext();
            // for Tomcat
            Context envContext = (Context) initialContext.lookup("java:comp/env");
            DataSource ds = (DataSource) envContext.lookup(dsName);
            // for Orion
            //DataSource ds = (DataSource) initialContext.lookup(dsName);
            dbConnection = ds.getConnection();
            //System.out.println("Open database connection through data source "+dsName+".");
        } catch (Exception e) {
            System.out.println("Exception, unable to establish connection through data source: " + e);
        }
        return dbConnection;
    }

    /**
     * Проверяет наличие соединения с базой данных.
     * @param dbConn
     * @return
     */
    public boolean checkConnection(Connection dbConn) {
        boolean OK = true;
        if (dbConn == null) {
            return false;
        }
        try {
            if (dbConn.isClosed()) {
                OK = false;
            }
        } catch (SQLException e) {
            System.out.println("Exception, unable to check connection: " + e);
        }
        return OK;
    }

    /**
     * Закрывает соединение с базой данных.
     * @param dbConnection ссылка на соединение
     * @param pStmt
     * @param rs
     */
    public static void closeConnection(Connection dbConnection, PreparedStatement pStmt, ResultSet rs) {
        closeConnection(dbConnection, pStmt, null, rs);
    }

    /**
     * Закрывает соединение с базой данных.
     * @param dbConnection ссылка на соединение
     * @param pStmt
     * @param stmt
     * @param rs
     */
    public static void closeConnection(Connection dbConnection, PreparedStatement pStmt, Statement stmt, ResultSet rs) {
        if (pStmt != null) {
            try {
                pStmt.close();
            } catch (SQLException ex) {
                System.out.println("SQLException: " + ex);
            }
        }

        if (stmt != null) {
            try {
                stmt.close();
            } catch (SQLException ex) {
                System.out.println("SQLException: " + ex);
            }
        }

        if (rs != null) {
            try {
                rs.close();
            } catch (SQLException ex) {
                System.out.println("SQLException: " + ex);
            }
        }
        if (dbConnection == null) {
            return;
        }
        try {
            dbConnection.close();
        } catch (Exception e) {
            System.out.println("Exception, unable to close database connection: " + e);
        }
    }

    /**
     * Закрывает соединение с базой данных.
     *	@param dbConnection ссылка на соединение
     */
    public static void closeConnection(Connection dbConnection) {
        closeConnection(dbConnection, null, null);
    }

    public static void closeConnection(Connection dbConnection, Statement stmt, ResultSet rs) {
        closeConnection(dbConnection, null, stmt, rs);
    }
}
